﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace Hierarchy_Maker
{
    
    public class MainWindowVM: BindableObject
    {
        private WorkItemStore _store;
        private TfsTeamProjectCollection _tfs;
        // List of link types
        public ObservableCollection<LinkTypeItem> LinkItemTypes { get; set; }
        // List of workitem types in the project(s) we are working with
        public ObservableCollection<WitType> WorkItemTypes { get; set; }
        // List of projects we are working with.
        public Project CurrentProject { get; set; }
        // Collection of Parent Workitems to be changed
        public ObservableCollection<Wit> ParentWorkItems { get; set; }
        
        // The types that are going to be linked as parent child (if they have a different kind of link)
        public WitType ParentWorkItemType { get; set; }
        public WitType ChildWorkItemType { get; set; }

        public SimpleCommand<object> SelectProjectCommand { get; set; }
        public SimpleCommand<object> MakeItGoCommand { get; set; }

        // Indicator to say if this is connected.
        private bool _connected;
        public bool Connected
        {
            get { return _connected; }
            set
            {
                _connected = value;
                StatusText = _connected ? "Status: Connected" : "Status: Not Connected";
                base.RaisePropertyChanged("StatusText");
            }
        }
        // Text to show if we are connected to TFS or not.
        public String StatusText { get; private set; }

        public MainWindowVM()
        {
            SelectProjectCommand = new SimpleCommand<object>
                                       {
                                           ExecuteDelegate = x => SelectProject(),
                                           CanExecuteDelegate = x => !Connected
                                       };

            MakeItGoCommand = new SimpleCommand<object>()
                                  {
                                      ExecuteDelegate = x => MakeItGo()
                                  };
            LinkItemTypes = new ObservableCollection<LinkTypeItem>();
            WorkItemTypes = new ObservableCollection<WitType>();
            ParentWorkItems = new ObservableCollection<Wit>();
            Connected = false;
        }

        // Method used to select the project we are working with
        public void SelectProject()
        {
            TeamProjectPicker pp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);
            pp.ShowDialog();

            if (pp.SelectedTeamProjectCollection != null)
            {
                _tfs = pp.SelectedTeamProjectCollection;
                pp.SelectedTeamProjectCollection.EnsureAuthenticated();
                _store = (WorkItemStore)pp.SelectedTeamProjectCollection.GetService(typeof(WorkItemStore));
                var projectInfos = pp.SelectedProjects.ToList();

                SetProject(projectInfos);
                
                FillLinkTypes();
                Connected = true;
                FillWorkItemTypes();
            }
        }

        private void SetProject(IEnumerable<ProjectInfo> projectInfos)
        {
            foreach (ProjectInfo projectInfo in projectInfos)
            {
                foreach (Project project in _store.Projects)
                {
                    if (project.Uri.ToString() == projectInfo.Uri)
                    {
                        CurrentProject = project;
                        // If somehow we had more than one project returned then we will just take the first.
                        return;
                    }
                }
            }
        }

        // Method to get all the different link types in the project.
        private void FillLinkTypes()
        {
            LinkItemTypes.Clear();
            foreach (WorkItemLinkType type in _store.WorkItemLinkTypes)
            {
                LinkItemTypes.Add(new LinkTypeItem(type));
            }
            base.RaisePropertyChanged("LinkItemTypes");
        }

        // Fill up the list of workitem types we are going to work with
        private void FillWorkItemTypes()
        {
            WorkItemTypes.Clear();

            foreach (WorkItemType workItemType in CurrentProject.WorkItemTypes)
            {
                WorkItemTypes.Add(new WitType(workItemType));
            }

            base.RaisePropertyChanged("WorkItemTypes");
        }

        // Get the items of the types in the parent group
        private void FillParentList()
        {
            string wiql =   "SELECT [System.Id], [System.Title], [System.Description] " +
                            "FROM WorkItems " +
                            "WHERE [System.TeamProject] = '" + CurrentProject.Name + "' "+
                            "       AND [System.WorkItemType] = '" + ParentWorkItemType + "' ";
            foreach (WorkItem workItem in _store.Query(wiql))
            {
                ParentWorkItems.Add(new Wit(workItem));
            }
            base.RaisePropertyChanged("ParentWorkItems");
        }


        public void MakeItGo()
        {
            FillParentList();
            foreach (Wit parentWorkItem in ParentWorkItems)
            {
                // Because we are going to be messing with the links, we need to get a copy of
                // them here.  (Before we add and subtract from them)
                List<WorkItemLink> workItemLinks = parentWorkItem.WorkItemLinks.Cast<WorkItemLink>().ToList();

                foreach (WorkItemLink link in workItemLinks)
                {
                    var childWorkItem = _store.GetWorkItem(link.TargetId);
                    if (childWorkItem.Type == ChildWorkItemType.Type)
                    {
                        if (link.LinkTypeEnd.Name == "Related")
                        {
                            // If we have a match then check the link type and if it is
                            // Relational then change it to be Hierarchical

                            bool linkCreated = CreateHierarchicalLink(parentWorkItem.WorkItem, childWorkItem);
                            if (linkCreated)
                            {
                                // If the link was created then remove the orginal link
                                parentWorkItem.WorkItemLinks.Remove(link);
                                parentWorkItem.Save();
                            }
                        }
                    }

                }
            }
        }

        private bool CreateHierarchicalLink(WorkItem parentWorkItem, WorkItem childWorkItem)
        {
            try
            {
                //Define what type of link to add.
                //Child, Parent etc...
                WorkItemLinkTypeEnd linkTypeEnd = _store.WorkItemLinkTypes.LinkTypeEnds["Child"];
                //Add the link as related link.
                parentWorkItem.Links.Add(new RelatedLink(linkTypeEnd, childWorkItem.Id));
                parentWorkItem.Save();
                //MessageBox.Show(string.Format("Work Item {0}, is {1} of Work Item {2}",
                //    parentWorkItem.Id, "a Child", childWorkItem.Id),
                //    "Relation Saved", MessageBoxButton.OK, MessageBoxImage.Information);

                return true;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message, "Cannot Save Work Item Relation", MessageBoxButton.OK,
                //    MessageBoxImage.Error);
            }
            return false;
        }
        
    }
}
